
/**
 * @file
 * A simple program to that publishes the current time whenever ENTER is pressed.
 */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "mqtt.h"
#include "templates/posix_sockets.h"


 /**
  * @brief The function that would be called whenever a PUBLISH is received.
  *
  * @note This function is not used in this example.
  */
void publish_callback(void** unused, struct mqtt_response_publish* published);

/**
 * @brief The client's refresher. This function triggers back-end routines to
 *        handle ingress/egress traffic to the broker.
 *
 * @note All this function needs to do is call \ref __mqtt_recv and
 *       \ref __mqtt_send every so often. I've picked 100 ms meaning that
 *       client ingress/egress traffic will be handled every 100 ms.
 */
void* client_refresher(void* client);

/**
 * @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
 */
void exit_example(int status, int sockfd, pthread_t* client_daemon);

#define IOTSHARP_CLIENTID "clientid89f866fced124f6e902515705f78148a"
#define IOTSHARP_ACCESSTOKEN "3cb97cd31fbc40b08d12ec47a6fad622"
/**
 * A simple program to that publishes the current time whenever ENTER is pressed.
 */
int main(int argc, const char* argv[])
{
	const char* addr;
	const char* port;
	const char* topic;

	/* get address (argv[1] if present) */
	if (argc > 1) {
		addr = argv[1];
	}
	else {
		addr = "127.0.0.1";
	}

	/* get port number (argv[2] if present) */
	if (argc > 2) {
		port = argv[2];
	}
	else {
		port = "1883";
	}

	/* get the topic name to publish */
	if (argc > 3) {
		topic = argv[3];
	}
	else {
		topic = "/devices/me/telemetry";
	}

	/* open the non-blocking TCP socket (connecting to the broker) */
	int sockfd = open_nb_socket(addr, port);

	if (sockfd == -1) {
		perror("Failed to open socket: ");
		exit_example(EXIT_FAILURE, sockfd, NULL);
	}

	/* setup a client */
	struct mqtt_client client;
	uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
	uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
	mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
	mqtt_connect(&client, IOTSHARP_CLIENTID, NULL, NULL, 0, IOTSHARP_ACCESSTOKEN, NULL, 0, 400);

	/* check that we don't have any errors */
	if (client.error != MQTT_OK) {
		fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
		exit_example(EXIT_FAILURE, sockfd, NULL);
	}

	/* start a thread to refresh the client (handle egress and ingree client traffic) */
	pthread_t client_daemon;
	if (pthread_create(&client_daemon, NULL, client_refresher, &client)) {
		fprintf(stderr, "Failed to start client daemon.\n");
		exit_example(EXIT_FAILURE, sockfd, NULL);

	}

	/* start publishing the time */
	printf("%s is ready to begin publishing the time.\n", argv[0]);
	printf("Press ENTER to publish the current time.\n");
	printf("Press CTRL-D (or any other key) to exit.\n\n");
	while (fgetc(stdin) == '\n') {
		/* get the current time */
		time_t timer;
		time(&timer);
		struct tm* tm_info = localtime(&timer);
		char timebuf[26];
		strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);

		/* print a message */
		char application_message[256];
		snprintf(application_message, sizeof(application_message), "{\"mydatetimei\":\"%s\"}", timebuf);
		printf("%s published : \"%s\"", argv[0], application_message);

		/* publish the time */
		mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_0);

		/* check for errors */
		if (client.error != MQTT_OK) {
			fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
			exit_example(EXIT_FAILURE, sockfd, &client_daemon);
		}
	}

	/* disconnect */
	printf("\n%s disconnecting from %s\n", argv[0], addr);
	sleep(1);

	/* exit */
	exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
}

void exit_example(int status, int sockfd, pthread_t* client_daemon)
{
	if (sockfd != -1) close(sockfd);
	if (client_daemon != NULL) pthread_cancel(*client_daemon);
	exit(status);
}



void publish_callback(void** unused, struct mqtt_response_publish* published)
{
	/* not used in this example */
}

void* client_refresher(void* client)
{
	while (1)
	{
		mqtt_sync((struct mqtt_client*) client);
		usleep(100000U);
	}
	return NULL;
}